`timescale 1ns / 1ps

// Simple Dual Port RAM with output handshake
module zq_sdpram_hs
#(
    parameter ADDR_WIDTH = 8,
    parameter DATA_WIDTH = 128,
    parameter DEPTH = 192,              // ADDR_WIDTH >= $clog2(DEPTH)
    parameter LATENCY = 2,              // read latency
    parameter RAMTYPE = "auto"          // auto, block, distributed, register
)
(
    input   clk,
    input   rst,

    // output  write_rdy == 1
    input   write_vld,
    input   [ADDR_WIDTH-1: 0]    addr_w,
    input   [DATA_WIDTH-1: 0]    din,

    output  read_rdy,
    input   read_vld,
    input   [ADDR_WIDTH-1: 0]    addr_r,

    input   out_rdy,
    output  out_vld,
    output  [DATA_WIDTH-1: 0]    dout
);

wire ena_r;
assign ena_r = ~out_vld | out_rdy;
assign read_rdy = ena_r;

shift_reg_rst #(
    .N     ( LATENCY ),
    .WIDTH (       1 )
)
inst_vaild_chain (
    .clk                     ( clk      ),
    .rst                     ( rst      ),

    .clken                   ( ena_r    ),
    .i_data                  ( read_vld ),
    .o_data                  (  out_vld )
);

zq_sdpram #(
    .ADDR_WIDTH ( ADDR_WIDTH ),
    .DATA_WIDTH ( DATA_WIDTH ),
    .DEPTH      (      DEPTH ),
    .LATENCY    ( LATENCY    ),
    .RAMTYPE    ( RAMTYPE    )
)
inst_sdpram (
    .clk                     ( clk       ),

    .ena_w                   ( write_vld ),
    .wea                     ( 1'b1      ),
    .addr_w                  ( addr_w   ),
    .din                     ( din      ),

    .ena_r                   ( ena_r    ),
    .addr_r                  ( addr_r   ),
    .dout                    ( dout     )
);

endmodule


// Single Port ROM with handshake
module zq_sprom_hs
#(
    parameter ADDR_WIDTH = 10,
    parameter DATA_WIDTH = 1280,
    parameter DEPTH = 768,              // ADDR_WIDTH >= $clog2(DEPTH)
    parameter LATENCY = 2,
    parameter ROMTYPE = "block",        // block or distributed
    parameter ROMFILE = "L9_PW.mem"
)
(
    input   clk,
    input   rst,
    
    output  read_rdy,
    input   read_vld,
    input   [ADDR_WIDTH-1: 0]    addr,

    input   out_rdy,
    output  out_vld,
    output  [DATA_WIDTH-1: 0]    dout
);

wire ena;
assign ena = ~out_vld | out_rdy;
assign read_rdy = ena;

shift_reg_rst #(
    .N     ( LATENCY ),
    .WIDTH (       1 )
)
inst_vaild_chain (
    .clk                     ( clk      ),
    .rst                     ( rst      ),

    .clken                   ( ena      ),
    .i_data                  ( read_vld ),
    .o_data                  (  out_vld )
);

zq_spram #(
    .ADDR_WIDTH ( ADDR_WIDTH ),
    .DATA_WIDTH ( DATA_WIDTH ),
    .DEPTH      (      DEPTH ),
    .LATENCY    ( LATENCY    ),
    .RAMTYPE    ( ROMTYPE    ),
    .RAMFILE    ( ROMFILE    )
)
inst_sprom (
    .clk                     ( clk    ),
    .ena                     ( ena    ),
    .wea                     ( 1'b0   ),
    .addr                    ( addr   ),
    .din                     ( {DATA_WIDTH{1'b0}} ),

    .dout                    ( dout   )
);

endmodule
